close

macvlan 簡介

macvlan 是 linux kernel 比較新的特性,可以通過以下方法判斷當前系統是否支持:

$ modprobe macvlan
$ lsmod | grep macvlan
  macvlan    19046    0

如果第一個命令報錯,或者第二個命令沒有返回,則說明當前系統不支持 macvlan,需要升級系統或者升級內核。

macvlan 允許你在主機的一個網絡接口上配置多個虛擬的網絡接口,這些網絡 interface 有自己獨立的 mac 地址,也可以配置上 ip 地址進行通信。macvlan 下的虛擬機或者容器網絡和主機在同一個網段中,共享同一個廣播域。macvlan 和 bridge 比較相似,但因為它省去了 bridge 的存在,所以配置和調試起來比較簡單,而且效率也相對高。除此之外,macvlan 自身也完美支持 VLAN。

如果希望容器或者虛擬機放在主機相同的網絡中,享受已經存在網絡棧的各種優勢,可以考慮 macvlan。

各個 linux 發行版對 macvlan 的支持

macvlan 對kernel 版本依賴:Linux kernel v3.9–3.19 and 4.0+。幾個重要發行版支持情況:

  • ubuntu:>= saucy(13.10)
  • RHEL(Red Hat Enterprise Linux): >= 7.0(3.10.0)
  • Fedora: >=19(3.9)
  • Debian: >=8(3.16)

各個發行版的 kernel 都可以自行手動升級,具體操作可以參考官方提供的文檔。

以上版本信息參考了這些資料:

四種模式

  • private mode:過濾掉所有來自其他 macvlan 接口的報文,因此不同 macvlan 接口之間無法互相通信
  • vepa(Virtual Ethernet Port Aggregator) mode: 需要主接口連接的交換機支持 VEPA/802.1Qbg 特性。所有發送出去的報文都會經過交換機,交換機作為再發送到對應的目標地址(即使目標地址就是主機上的其他 macvlan 接口),也就是 hairpin mode 模式,這個模式用在交互機上需要做過濾、統計等功能的場景。
  • bridge mode:通過虛擬的交換機講主接口的所有 macvlan 接口連接在一起,這樣的話,不同 macvlan 接口之間能夠直接通信,不需要將報文發送到主機之外。這個模式下,主機外是看不到主機上 macvlan interface 之間通信的報文的。
  • passthru mode:暫時沒有搞清楚這個模式要解決的問題

VEPA 和 passthru 模式下,兩個 macvlan 接口之間的通信會經過主接口兩次:第一次是發出的時候,第二次是返回的時候。這樣會影響物理接口的寬帶,也限制了不同 macvlan 接口之間通信的速度。如果多個 macvlan 接口之間通信比較頻繁,對於性能的影響會比較明顯。

private 模式下,所有的 macvlan 接口都不能互相通信,對性能影響最小。

bridge 模式下,數據報文是通過內存直接轉發的,因此效率會高一些,但是會造成 CPU 額外的計算量。

NOTE:如果要手動分配 mac 地址,請注意本地的 mac 地址最高位字節的低位第二個 bit 必須是 1。比如 02:xx:xx:xx:xx:xx

實驗

為了方便演示,我們會創建出來兩個 macvlan 接口,分別放到不同的 network namespace 裡。整個實驗的網絡拓撲結構如下:

network topology

圖片來源

首先還是創建兩個 network namespace:

[root@localhost ~]# ip netns add net1
[root@localhost ~]# ip netns add net2

然後創建 macvlan 接口:

[root@localhost ~]# ip link add link enp0s8 mac1 type macvlan
[root@localhost ~]# ip link
23: mac1@enp0s8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT
    link/ether e2:80:1c:ba:59:9c brd ff:ff:ff:ff:ff:ff

創建的格式為 ip link add link <PARENT> <NAME> type macvlan,其中 <PARENT> 是 macvlan 接口的父 interface 名稱,<NAME> 是新建的 macvlan 接口的名稱,這個名字可以任意取。使用 ip link 可以看到我們剛創建的 macvlan 接口,除了它自己的名字之外,後面還跟著父接口的名字。

下面就是把創建的 macvlan 放到 network namespace 中,配置好 ip 地址,然後啟用它:

[root@localhost ~]# ip link set mac1@enp0s8 netns net1
Cannot find device "mac1@enp0s8"
[root@localhost ~]# ip link set mac1 netns net1
[root@localhost ~]# ip netns exec net1 ip link
23: mac1@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT
    link/ether e2:80:1c:ba:59:9c brd ff:ff:ff:ff:ff:ff
[root@localhost ~]# ip netns exec net1 ip link set mac1 name eth0
[root@localhost ~]# ip netns exec net1 ip link
23: eth0@if3: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT
    link/ether e2:80:1c:ba:59:9c brd ff:ff:ff:ff:ff:ff
[root@localhost ~]# ip netns exec net1 ip addr add 192.168.8.120/24 dev eth0
[root@localhost ~]# ip netns exec net1 ip link set eth0 up

同理可以配置另外一個 macvlan 接口,可以測試兩個 ip 的連通性:

[root@localhost ~]# docker exec 1444 ping -c 3 192.168.8.120
PING 192.168.8.120 (192.168.8.120): 56 data bytes
64 bytes from 192.168.8.120: seq=0 ttl=64 time=0.130 ms
64 bytes from 192.168.8.120: seq=1 ttl=64 time=0.099 ms
64 bytes from 192.168.8.120: seq=2 ttl=64 time=0.083 ms

--- 192.168.8.120 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.083/0.104/0.130 ms

在 docker 中的使用

docker1.12 版本也正式支持了 macvlan 和 ipvlan 網絡模式。

創建 macvlan 網絡

管理 macvlan 和其他類型的網絡類似,通過 docker network 子命令就能實現。創建 macvlan 網絡的時候,需要知道主機的網段和網關地址,虛擬網絡要依附的物理網卡。

[root@localhost ~]# docker network create -d macvlan --subnet=192.168.8.0/24 --gateway=192.168.8.1 -o parent=enp0s8 mcv
9fad35e54a2f53c9314626f89cf8a705799ed382ddac01c865be1f4d04fdcb8f
[root@localhost ~]# docker network ls
NETWORK ID          NAME                DRIVER              SCOPE
e06b6e00dd3b        bridge              bridge              local
823b7bb07c41        host                host                local
9fad35e54a2f        mcv                 macvlan             local
dc7c667aca19        none                null                local

選項說明:

  • subnet:網絡 CIDR 地址
  • gateway:網關地址
  • aux-address:不要分配給容器的 ip 地址。字典,以 key=value 對出現
  • ip-range:指定具體的 ip 分配區間,也是 CIDR 格式,必須是 subnet 指定範圍的子集
  • opt(o):和 macvlan driver 相關的選項,以 key=value 的格式出現
    • parent=eth0: 指定 parent interface
    • macvlan_mode:macvlan 模式,默認是 bridge

運行容器

創建好網絡之後,我們就可以使用剛創建的網絡運行兩個容器,測試網絡的連通性。

[root@localhost ~]# docker run --net=mac192 -d --rm alpine top
5e950cf86cda7b4e6fc4bd869834943edacaaf969051293021c75330bbc18b53
[root@localhost ~]# docker run --net=mac192 -d --rm alpine top
9067c54aac79e65b3193a137e95a180a7e5cc4a2845cc664f53c17a244be3853
[root@localhost ~]# docker ps
CONTAINER ID        IMAGE               COMMAND             CREATED             STATUS              PORTS               NAMES
9067c54aac79        alpine              "top"               7 seconds ago       Up 6 seconds                            sharp_hodgkin
5e950cf86cda        alpine              "top"               8 seconds ago       Up 7 seconds                            peaceful_chandrasekhar

[root@localhost ~]# docker exec 906 ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
16: eth0@if3: <BROADCAST,MULTICAST,UP,LOWER_UP,M-DOWN> mtu 1500 qdisc noqueue state UNKNOWN
    link/ether 02:42:c0:a8:08:03 brd ff:ff:ff:ff:ff:ff
    inet 192.168.8.3/24 scope global eth0
       valid_lft forever preferred_lft forever
    inet6 fe80::42:c0ff:fea8:803/64 scope link
       valid_lft forever preferred_lft forever
[root@localhost ~]# docker exec 5e9 ping -c 3 192.168.8.3
PING 192.168.8.3 (192.168.8.3): 56 data bytes
64 bytes from 192.168.8.3: seq=0 ttl=64 time=0.226 ms
64 bytes from 192.168.8.3: seq=1 ttl=64 time=0.076 ms
64 bytes from 192.168.8.3: seq=2 ttl=64 time=0.095 ms

--- 192.168.8.3 ping statistics ---
3 packets transmitted, 3 packets received, 0% packet loss
round-trip min/avg/max = 0.076/0.132/0.226 ms

需要注意的是,從容器中是無法訪問所在主機地址的:

[root@localhost ~]# docker exec 5e9 ping -c 3 192.168.8.110
PING 192.168.8.110 (192.168.8.110): 56 data bytes

--- 192.168.8.110 ping statistics ---
3 packets transmitted, 0 packets received, 100% packet loss

這是 macvlan 的特性,目的是為了更好地實現網絡的隔離,和 docker 無關。

參考資料

轉載自: http://cizixs.com/2017/02/14/network-virtualization-macvlan

arrow
arrow
    創作者介紹
    創作者 lyt0112 的頭像
    lyt0112

    小廷的部落格

    lyt0112 發表在 痞客邦 留言(0) 人氣()